home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / oper_sys / kerberos / pc / krb_libk.lha / Lib / KRB / TF_UTIL.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-08-01  |  19.0 KB  |  721 lines

  1. /*
  2.  * $Source: /afs/athena.mit.edu/astaff/project/kerberos/src/lib/krb/RCS/tf_util.c,v $
  3.  * $Author: jon $
  4.  *
  5.  * Copyright 1987, 1988 by the Massachusetts Institute of Technology.
  6.  *
  7.  * For copying and distribution information, please see the file
  8.  * <mit-copyright.h>.
  9.  */
  10.  
  11. #ifndef lint
  12. static char rcsid_tf_util_c[] =
  13. "$Id: tf_util.c,v 4.9 90/03/10 19:19:45 jon Exp $";
  14. #endif /* lint */
  15.  
  16. #include <mit_copy.h>
  17. #include <conf.h>
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <errno.h>
  21. #include <string.h>
  22. #include <sys\types.h>
  23. #include <sys\stat.h>
  24. #ifdef IBMPC
  25. #include <dos.h>
  26. #include <fcntl.h>
  27. #ifdef __BORLANDC__
  28. #define _enable enable
  29. #define _disable disable
  30. #endif /* BORLANDC */
  31. #else
  32. #include <sys/file.h> 
  33. #endif IBMPC
  34. #include <krb.h>
  35.  
  36. #ifdef TKT_SHMEM
  37. #include <sys/param.h>
  38. #include <sys/ipc.h>
  39. #include <sys/shm.h>
  40. #endif /* TKT_SHMEM */
  41.  
  42. #define TOO_BIG -1
  43. #define TF_LCK_RETRY ((unsigned)2)    /* seconds to sleep before
  44.                      * retry if ticket file is
  45.                      * locked */
  46. extern int krb_debug;
  47. typedef long off_t;
  48.  
  49. #ifdef TKT_SHMEM
  50. char *krb_shm_addr = 0;
  51. static char *tmp_shm_addr = 0;
  52. static char krb_dummy_skey[8] = {0,0,0,0,0,0,0,0};
  53.  
  54. char *shmat();
  55. #endif /* TKT_SHMEM */
  56.  
  57. /*
  58.  * fd must be initialized to something that won't ever occur as a real
  59.  * file descriptor. Since open(2) returns only non-negative numbers as
  60.  * valid file descriptors, and tf_init always stuffs the return value
  61.  * from open in here even if it is an error flag, we must
  62.  *     a. Initialize fd to a negative number, to indicate that it is
  63.  *        not initially valid.
  64.  *    b. When checking for a valid fd, assume that negative values
  65.  *       are invalid (ie. when deciding whether tf_init has been
  66.  *       called.)
  67.  *    c. In tf_close, be sure it gets reinitialized to a negative
  68.  *       number. 
  69.  */
  70. #ifdef IBMPC
  71. static tkt_header far *hdr=NULL;    /* ticket memory header */
  72. static char far *curptr;    /* next byte to read */
  73. static char far *lastptr;    /* end of ticket file */ 
  74. static  fd = -1;
  75. #else
  76. static    curpos;                /* Position in tfbfr */
  77. static    lastpos;            /* End of tfbfr */
  78. static    char tfbfr[BUFSIZ];        /* Buffer for ticket data */
  79. #endif /* IBMPC */
  80.  
  81. static tf_gets(char*,int), tf_read(char*,unsigned);
  82.  
  83. /*
  84.  * This file contains routines for manipulating the ticket cache file.
  85.  *
  86.  * The ticket file is in the following format:
  87.  *
  88.  *      principal's name        (null-terminated string)
  89.  *      principal's instance    (null-terminated string)
  90.  *      CREDENTIAL_1
  91.  *      CREDENTIAL_2
  92.  *      ...
  93.  *      CREDENTIAL_n
  94.  *      EOF
  95.  *
  96.  *      Where "CREDENTIAL_x" consists of the following fixed-length
  97.  *      fields from the CREDENTIALS structure (see "krb.h"):
  98.  *
  99.  *              char            service[ANAME_SZ]
  100.  *              char            instance[INST_SZ]
  101.  *              char            realm[REALM_SZ]
  102.  *              C_Block         session
  103.  *              int             lifetime
  104.  *              int             kvno
  105.  *              KTEXT_ST        ticket_st
  106.  *              long            issue_date
  107.  *
  108.  * Short description of routines:
  109.  *
  110.  * tf_init() opens the ticket file and locks it.
  111.  *
  112.  * tf_get_pname() returns the principal's name.
  113.  *
  114.  * tf_get_pinst() returns the principal's instance (may be null).
  115.  *
  116.  * tf_get_cred() returns the next CREDENTIALS record.
  117.  *
  118.  * tf_save_cred() appends a new CREDENTIAL record to the ticket file.
  119.  *
  120.  * tf_close() closes the ticket file and releases the lock.
  121.  *
  122.  * tf_gets() returns the next null-terminated string.  It's an internal
  123.  * routine used by tf_get_pname(), tf_get_pinst(), and tf_get_cred().
  124.  *
  125.  * tf_read() reads a given number of bytes.  It's an internal routine
  126.  * used by tf_get_cred().
  127.  */
  128.  
  129. #ifdef IBMPC
  130. int lock_tkt(tkt_header far *hdr,int wrflag) 
  131. /* attempt to lock ticket file, returns 1 for success.
  132.     wrflag is true if we need to lock for write */
  133. {
  134.     _disable();
  135.     if (hdr->sema<0 || wrflag && hdr->sema) {
  136.         _enable();
  137.         if (krb_debug)
  138.             printf("Old ticket file in use.\n");
  139.         return 0;
  140.     } 
  141.     if (wrflag)
  142.         hdr->sema=-1;    /* lock for write */
  143.     else
  144.         hdr->sema++;    /* lock for one more reader */
  145.     _enable();
  146.     return 1;
  147. }
  148.  
  149. void unlock_tkt(tkt_header far *hdr)
  150. {
  151.     _disable();
  152.     if (hdr->sema<0)
  153.         hdr->sema=0;    /* unlock write */
  154.     else
  155.         hdr->sema--;    /* reduce one reader */
  156.     _enable();
  157. }
  158. tkt_header far * tkt_ptr()
  159. {
  160.     unsigned long segment;
  161.     char *value;
  162.  
  163.     return (tkt_header far*) 
  164.         ((value=getenv(TKT_ENV)) && (segment=atol(value)) ?
  165.             segment<<16 : 0UL);
  166. }
  167.  
  168. #endif    /* IBMPC */
  169.  
  170. /*
  171.  * tf_init() should be called before the other ticket file routines.
  172.  * It takes the name of the ticket file to use, "tf_name", and a
  173.  * read/write flag "rw" as arguments. 
  174.  *
  175.  * It tries to open the ticket file, checks the mode, and if everything
  176.  * is okay, locks the file.  If it's opened for reading, the lock is
  177.  * shared.  If it's opened for writing, the lock is exclusive. 
  178.  *
  179.  * Returns KSUCCESS if all went well, otherwise one of the following: 
  180.  *
  181.  * NO_TKT_FIL   - file wasn't there
  182.  * TKT_FIL_ACC  - file was in wrong mode, etc.
  183.  * TKT_FIL_LCK  - couldn't lock the file, even after a retry
  184.  */
  185.  
  186. tf_init(tf_name, rw)
  187.     char   *tf_name;
  188. {
  189.     int     wflag;
  190.     struct stat stat_buf;
  191. #ifdef TKT_SHMEM
  192.     char shmidname[MAXPATHLEN]; 
  193.     FILE *sfp;
  194.     int shmid;
  195. #endif
  196. #ifdef IBMPC
  197.     char *value;
  198.     unsigned segment;
  199. #endif
  200.  
  201.     switch (rw) {
  202.         case R_TKT_FIL:
  203.             wflag = 0;
  204.             break;
  205.         case W_TKT_FIL:
  206.             wflag = 1;
  207.             break;
  208.         default:
  209.             if (krb_debug) fprintf(stderr, "tf_init: illegal parameter\n");
  210.         return TKT_FIL_ACC;
  211.     }
  212. #ifdef IBMPC
  213.     
  214.     if ((hdr=tkt_ptr())==NULL) {
  215. #ifdef DEBUG
  216.         if (krb_debug)
  217.             printf("Ticket memory not reserved or"
  218.                 "corrupt environment variable\n");
  219. #endif
  220.         return NO_TKT_FIL;
  221.     }
  222.     
  223.     if (!lock_tkt(hdr,wflag)) 
  224.         return TKT_FIL_LCK;
  225.         
  226.     if (hdr->eof_ptr==sizeof(tkt_header)) {
  227.         unlock_tkt(hdr);
  228.         hdr=NULL;
  229. #ifdef DEBUG    
  230.         if (krb_debug)
  231.             printf("Ticket memory is empty\n");
  232. #endif 
  233.         return NO_TKT_FIL;
  234.     }
  235.     curptr=(char far *)hdr + sizeof(tkt_header);
  236.     lastptr=(char far*)hdr + hdr->eof_ptr;
  237.     fd=1;    /* tell everyone fd is opened! */
  238.     return (KSUCCESS);
  239.     
  240. #else    /* ! IBMPC */
  241.     if (stat(tf_name, &stat_buf) < 0)
  242.         switch (errno) {
  243.             case ENOENT:
  244.                 return NO_TKT_FIL;
  245.             default:
  246.                 return TKT_FIL_ACC;
  247.     }
  248. #ifdef TKT_SHMEM
  249.     (void) strcpy(shmidname, tf_name);
  250.     (void) strcat(shmidname, ".shm");
  251.     if (stat(shmidname,&stat_buf) < 0)
  252.     return(TKT_FIL_ACC);
  253.     if ((stat_buf.st_uid != me && me != 0) ||
  254.     ((stat_buf.st_mode & S_IFMT) != S_IFREG))
  255.     return TKT_FIL_ACC;
  256. #endif /* TKT_SHMEM */
  257.  
  258.     /*
  259.      * If "wflag" is set, open the ticket file in append-writeonly mode
  260.      * and lock the ticket file in exclusive mode.  If unable to lock
  261.      * the file, sleep and try again.  If we fail again, return with the
  262.      * proper error message. 
  263.      */
  264.  
  265.     curpos = sizeof(tfbfr);
  266.  
  267. #ifdef TKT_SHMEM
  268.     sfp = fopen(shmidname, "r");    /* only need read/write on the
  269.                        actual tickets */
  270.     if (sfp == 0)
  271.         return TKT_FIL_ACC;
  272.     shmid = -1;
  273.     {
  274.     char buf[BUFSIZ];
  275.     int val;            /* useful for debugging fscanf */
  276.     /* We provide our own buffer here since some STDIO libraries
  277.        barf on unbuffered input with fscanf() */
  278.  
  279.     setbuf(sfp, buf);
  280.     if ((val = fscanf(sfp,"%d",&shmid)) != 1) {
  281.         (void) fclose(sfp);
  282.         return TKT_FIL_ACC;
  283.     }
  284.     if (shmid < 0) {
  285.         (void) fclose(sfp);
  286.         return TKT_FIL_ACC;
  287.     }
  288.     (void) fclose(sfp);
  289.     }
  290.     /*
  291.     * global krb_shm_addr is initialized to 0.  Ultrix bombs when you try and
  292.     * attach the same segment twice so we need this check.
  293.     */
  294.     if (!krb_shm_addr) {
  295.         if ((krb_shm_addr = shmat(shmid,0,0)) == -1){
  296.         if (krb_debug)
  297.             fprintf(stderr,
  298.                 "cannot attach shared memory for segment %d\n",
  299.                 shmid);
  300.         krb_shm_addr = 0;    /* reset so we catch further errors */
  301.         return TKT_FIL_ACC;
  302.         }
  303.     }
  304.     tmp_shm_addr = krb_shm_addr;
  305. #endif /* TKT_SHMEM */
  306.     
  307.     if (wflag) {
  308.         fd = open(tf_name, O_RDWR);
  309.         if (fd < 0) {
  310.             return TKT_FIL_ACC;
  311.             }
  312.         return KSUCCESS;
  313.     }
  314.     /*
  315.      * Otherwise "wflag" is not set and the ticket file should be opened
  316.      * for read-only operations and locked for shared access. 
  317.      */
  318.  
  319.     fd = open(tf_name, O_RDONLY);
  320.     if (fd < 0) {
  321.         return TKT_FIL_ACC;
  322.     }
  323.     return KSUCCESS;
  324. #endif /* IBMPC */
  325. }
  326.  
  327. /*
  328.  * tf_get_pname() reads the principal's name from the ticket file. It
  329.  * should only be called after tf_init() has been called.  The
  330.  * principal's name is filled into the "p" parameter.  If all goes well,
  331.  * KSUCCESS is returned.  If tf_init() wasn't called, TKT_FIL_INI is
  332.  * returned.  If the name was null, or EOF was encountered, or the name
  333.  * was longer than ANAME_SZ, TKT_FIL_FMT is returned. 
  334.  */
  335.  
  336. tf_get_pname(p)
  337.     char   *p;
  338. {
  339.     if (fd < 0) {
  340.         if (krb_debug)
  341.             fprintf(stderr, "tf_get_pname called before tf_init.\n");
  342.         return TKT_FIL_INI;
  343.     }
  344.     if (tf_gets(p, ANAME_SZ) < 2)    /* can't be just a null */
  345.         return TKT_FIL_FMT;
  346.     return KSUCCESS;
  347. }
  348.  
  349. /*
  350.  * tf_get_pinst() reads the principal's instance from a ticket file.
  351.  * It should only be called after tf_init() and tf_get_pname() have been
  352.  * called.  The instance is filled into the "inst" parameter.  If all
  353.  * goes well, KSUCCESS is returned.  If tf_init() wasn't called,
  354.  * TKT_FIL_INI is returned.  If EOF was encountered, or the instance
  355.  * was longer than ANAME_SZ, TKT_FIL_FMT is returned.  Note that the
  356.  * instance may be null. 
  357.  */
  358.  
  359. tf_get_pinst(inst)
  360.     char   *inst;
  361. {
  362.     if (fd < 0) {
  363.         if (krb_debug)
  364.             fprintf(stderr, "tf_get_pinst called before tf_init.\n");
  365.         return TKT_FIL_INI;
  366.     }
  367.     if (tf_gets(inst, INST_SZ) < 1)
  368.         return TKT_FIL_FMT;
  369.     return KSUCCESS;
  370. }
  371.  
  372. /*
  373.  * tf_get_cred() reads a CREDENTIALS record from a ticket file and fills
  374.  * in the given structure "c".  It should only be called after tf_init(),
  375.  * tf_get_pname(), and tf_get_pinst() have been called. If all goes well,
  376.  * KSUCCESS is returned.  Possible error codes are: 
  377.  *
  378.  * TKT_FIL_INI  - tf_init wasn't called first
  379.  * TKT_FIL_FMT  - bad format
  380.  * EOF          - end of file encountered
  381.  */
  382.  
  383. tf_get_cred(c)
  384.     CREDENTIALS *c;
  385. {
  386.     KTEXT   ticket = &c->ticket_st;    /* pointer to ticket */
  387.     int     k_errno;
  388.  
  389.     if (fd < 0) {
  390.         if (krb_debug)
  391.             fprintf(stderr, "tf_get_cred called before tf_init.\n");
  392.         return TKT_FIL_INI;
  393.     }
  394.     if ((k_errno = tf_gets(c->service, SNAME_SZ)) < 2)
  395.         switch (k_errno) {
  396.         case TOO_BIG:
  397.         case 1:        /* can't be just a null */
  398.             tf_close();
  399.             return TKT_FIL_FMT;
  400.         case 0:
  401.             return EOF;
  402.     }
  403.     if ((k_errno = tf_gets(c->instance, INST_SZ)) < 1)
  404.     switch (k_errno) {
  405.     case TOO_BIG:
  406.         return TKT_FIL_FMT;
  407.     case 0:
  408.         return EOF;
  409.     }
  410.     if ((k_errno = tf_gets(c->realm, REALM_SZ)) < 2)
  411.     switch (k_errno) {
  412.     case TOO_BIG:
  413.     case 1:        /* can't be just a null */
  414.         tf_close();
  415.         return TKT_FIL_FMT;
  416.     case 0:
  417.         return EOF;
  418.     }
  419.     if (
  420.         tf_read((char *) (c->session), KEY_SZ) < 1 ||
  421.         tf_read((char *) &(c->lifetime), sizeof(c->lifetime)) < 1 ||
  422.         tf_read((char *) &(c->kvno), sizeof(c->kvno)) < 1 ||
  423.         tf_read((char *) &(ticket->length), sizeof(ticket->length))
  424.         < 1 ||
  425.     /* don't try to read a silly amount into ticket->dat */
  426.         ticket->length > MAX_KTXT_LEN ||
  427.         tf_read((char *) (ticket->dat), ticket->length) < 1 ||
  428.         tf_read((char *) &(c->issue_date), sizeof(c->issue_date)) < 1
  429.     ) {
  430.         tf_close();
  431.         return TKT_FIL_FMT;
  432.     }
  433. #ifdef TKT_SHMEM
  434.     bcopy(tmp_shm_addr,c->session,KEY_SZ);
  435.     tmp_shm_addr += KEY_SZ;
  436. #endif /* TKT_SHMEM */
  437.     return KSUCCESS;
  438. }
  439.  
  440. /*
  441.  * tf_close() closes the ticket file and sets "fd" to -1. If "fd" is
  442.  * not a valid file descriptor, it just returns.  It also clears the
  443.  * buffer used to read tickets.
  444.  *
  445.  * The return value is not defined.
  446.  */
  447.  
  448. tf_close()
  449. {
  450. #ifdef IBMPC
  451.     if (hdr) {
  452.         hdr->eof_ptr=FP_OFF(lastptr);    /* ensure eof is set correctly */
  453.         unlock_tkt(hdr);
  454.         hdr=NULL;
  455.         curptr=lastptr=NULL;
  456.         fd=-1;        /* tell everyone ticket file is closed */
  457.     }
  458. #else /* !IBMPC */
  459.     if (!(fd < 0)) {
  460. #ifdef TKT_SHMEM
  461.     if (shmdt(krb_shm_addr)) {
  462.         /* what kind of error? */
  463.         if (krb_debug)
  464.         fprintf(stderr, "shmdt 0x%x: errno %d",krb_shm_addr, errno);
  465.     } else {
  466.         krb_shm_addr = 0;
  467.     }
  468. #endif TKT_SHMEM
  469.     (void) close(fd);
  470.     fd = -1;        /* see declaration of fd above */
  471.     }
  472.     memset(tfbfr,0, sizeof(tfbfr));
  473. #endif    /* IBMPC */
  474. }
  475.  
  476. /*
  477.  * tf_gets() is an internal routine.  It takes a string "s" and a count
  478.  * "n", and reads from the file until either it has read "n" characters,
  479.  * or until it reads a null byte. When finished, what has been read exists
  480.  * in "s". If it encounters EOF or an error, it closes the ticket file. 
  481.  *
  482.  * Possible return values are:
  483.  *
  484.  * n            the number of bytes read (including null terminator)
  485.  *              when all goes well
  486.  *
  487.  * 0            end of file or read error
  488.  *
  489.  * TOO_BIG      if "count" characters are read and no null is
  490.  *        encountered. This is an indication that the ticket
  491.  *        file is seriously ill.
  492.  */
  493.  
  494. static 
  495. tf_gets(s, n)
  496.     register char *s;
  497. {
  498.     register count;
  499. #ifdef IBMPC
  500.  
  501.     if (hdr==NULL) {
  502.         if (krb_debug)
  503.             fprintf(stderr, "tf_gets called before tf_init.\n");
  504.         return TKT_FIL_INI;
  505.     }
  506.     for (count = n - 1; count > 0; --count) {
  507.         if (curptr == lastptr) {
  508.             tf_close();
  509.             return 0;
  510.         }
  511.         *s = *curptr++;
  512. #else /* !IBMPC */
  513.  
  514.     if (fd < 0) {
  515.     if (krb_debug)
  516.         fprintf(stderr, "tf_gets called before tf_init.\n");
  517.     return TKT_FIL_INI;
  518.     }
  519.     for (count = n - 1; count > 0; --count) {
  520.     if (curpos >= sizeof(tfbfr)) {
  521.         lastpos = read(fd, tfbfr, sizeof(tfbfr));
  522.         curpos = 0;
  523.     }
  524.     if (curpos == lastpos) {
  525.         tf_close();
  526.         return 0;
  527.     }
  528.     *s = tfbfr[curpos++];
  529. #endif    /* IBMPC */
  530.     if (*s++ == '\0')
  531.         return (n - count);
  532.     }
  533.     tf_close();
  534.     return TOO_BIG;
  535. }
  536.  
  537. /*
  538.  * tf_read() is an internal routine.  It takes a string "s" and a count
  539.  * "n", and reads from the file until "n" bytes have been read.  When
  540.  * finished, what has been read exists in "s".  If it encounters EOF or
  541.  * an error, it closes the ticket file.
  542.  *
  543.  * Possible return values are:
  544.  *
  545.  * n        the number of bytes read when all goes well
  546.  *
  547.  * 0        on end of file or read error
  548.  */
  549.  
  550. static
  551. tf_read(s, n)
  552.     register char *s;
  553.     register unsigned n;
  554. {
  555.     register count;
  556.  
  557.     for (count = n; count > 0; --count) {
  558. #ifdef IBMPC
  559.         if (curptr == lastptr) {
  560.             tf_close();
  561.             return 0;
  562.         }
  563.         *s++ = *curptr++;
  564. #else /* !IBMPC */
  565.     if (curpos >= sizeof(tfbfr)) {
  566.         lastpos = read(fd, tfbfr, sizeof(tfbfr));
  567.         curpos = 0;
  568.     }
  569.     if (curpos == lastpos) {
  570.         tf_close();
  571.         return 0;
  572.     }
  573.     *s++ = tfbfr[curpos++];
  574. #endif    /* IBMPC */
  575.     }
  576.     return n;
  577. }
  578.      
  579. char   *tkt_string();
  580.  
  581. /*
  582.  * tf_save_cred() appends an incoming ticket to the end of the ticket
  583.  * file.  You must call tf_init() before calling tf_save_cred().
  584.  *
  585.  * The "service", "instance", and "realm" arguments specify the
  586.  * server's name; "session" contains the session key to be used with
  587.  * the ticket; "kvno" is the server key version number in which the
  588.  * ticket is encrypted, "ticket" contains the actual ticket, and
  589.  * "issue_date" is the time the ticket was requested (local host's time).
  590.  *
  591.  * Returns KSUCCESS if all goes well, TKT_FIL_INI if tf_init() wasn't
  592.  * called previously, and KFAILURE for anything else that went wrong.
  593.  */
  594.  
  595. tf_save_cred(service, instance, realm, session, lifetime, kvno,
  596.          ticket, issue_date)
  597.     char   *service;        /* Service name */
  598.     char   *instance;        /* Instance */
  599.     char   *realm;        /* Auth domain */
  600.     C_Block session;        /* Session key */
  601.     int     lifetime;        /* Lifetime */
  602.     int     kvno;        /* Key version number */
  603.     KTEXT   ticket;        /* The ticket itself */
  604.     long    issue_date;        /* The issue time */
  605. {
  606.     int i;
  607. #ifdef IBMPC
  608.     if (hdr==NULL) {        /* fd is ticket file as set by tf_init */
  609.       if (krb_debug)
  610.           fprintf(stderr, "tf_save_cred called before tf_init.\n");
  611.       return TKT_FIL_INI;
  612.     }
  613.     /* Find the end of the ticket file */
  614.     lastptr=(char far *)hdr+hdr->eof_ptr;
  615.  
  616.     /* Write the ticket and associated data */
  617.     /* check memory space */
  618.     if (hdr->eof_ptr+strlen(service)+strlen(instance)+strlen(realm)+3+
  619.         8+sizeof(int)*3+ticket->length+sizeof(long)>=hdr->buf_size)
  620.         goto bad;    /* Not enough space */
  621.     /* Service */
  622.     while (*lastptr++=*service++);
  623.     /* Instance */
  624.     while (*lastptr++=*instance++);
  625.     /* Realm */
  626.     while (*lastptr++=*realm++);
  627.     /* Session key */
  628.     for (i=0; i<8; i++)
  629.         *lastptr++=((char *) session) [i];
  630.     /* Lifetime */
  631.     for (i=0; i<sizeof(int); i++)
  632.         *lastptr++=((char *) &lifetime) [i];
  633.     /* Key vno */
  634.     for (i=0; i<sizeof(int); i++)
  635.         *lastptr++=((char *) &kvno) [i];
  636.     /* Tkt length */
  637.     for (i=0; i<sizeof(int); i++)
  638.         *lastptr++=((char *) &ticket->length) [i];
  639.     /* Ticket */
  640.     for (i=0; i<ticket->length; i++)
  641.         *lastptr++=((char *) ticket->dat) [i];
  642.      /* Issue date */
  643.     for (i=0; i<sizeof(long); i++)
  644.         *lastptr++=((char *) &issue_date) [i];
  645. #else  /* !IBMPC */
  646.     off_t   lseek();
  647.     int     count;        /* count for write */
  648. #ifdef TKT_SHMEM
  649.     int        *skey_check;
  650. #endif /* TKT_SHMEM */
  651.  
  652.     if (fd < 0) {        /* fd is ticket file as set by tf_init */
  653.       if (krb_debug)
  654.           fprintf(stderr, "tf_save_cred called before tf_init.\n");
  655.       return TKT_FIL_INI;
  656.     }
  657.     /* Find the end of the ticket file */
  658.     (void) lseek(fd, 0L, 2);
  659. #ifdef TKT_SHMEM
  660.     /* scan to end of existing keys: pick first 'empty' slot.
  661.        we assume that no real keys will be completely zero (it's a weak
  662.        key under DES) */
  663.  
  664.     skey_check = (int *) krb_shm_addr;
  665.  
  666.     while (*skey_check && *(skey_check+1))
  667.     skey_check += 2;
  668.     tmp_shm_addr = (char *)skey_check;
  669. #endif /* TKT_SHMEM */
  670.  
  671.     /* Write the ticket and associated data */
  672.     /* Service */
  673.     count = strlen(service) + 1;
  674.     if (write(fd, service, count) != count)
  675.     goto bad;
  676.     /* Instance */
  677.     count = strlen(instance) + 1;
  678.     if (write(fd, instance, count) != count)
  679.     goto bad;
  680.     /* Realm */
  681.     count = strlen(realm) + 1;
  682.     if (write(fd, realm, count) != count)
  683.     goto bad;
  684.     /* Session key */
  685. #ifdef TKT_SHMEM
  686.     bcopy(session,tmp_shm_addr,8);
  687.     tmp_shm_addr+=8;
  688.     if (write(fd,krb_dummy_skey,8) != 8)
  689.     goto bad;
  690. #else /* ! TKT_SHMEM */
  691.     if (write(fd, (char *) session, 8) != 8)
  692.     goto bad;
  693. #endif /* TKT_SHMEM */
  694.     /* Lifetime */
  695.     if (write(fd, (char *) &lifetime, sizeof(int)) != sizeof(int))
  696.     goto bad;
  697.     /* Key vno */
  698.     if (write(fd, (char *) &kvno, sizeof(int)) != sizeof(int))
  699.     goto bad;
  700.     /* Tkt length */
  701.     if (write(fd, (char *) &(ticket->length), sizeof(int)) !=
  702.     sizeof(int))
  703.     goto bad;
  704.     /* Ticket */
  705.     count = ticket->length;
  706.     if (write(fd, (char *) (ticket->dat), count) != count)
  707.     goto bad;
  708.     /* Issue date */
  709.     if (write(fd, (char *) &issue_date, sizeof(long))
  710.     != sizeof(long))
  711.     goto bad;
  712.  
  713. #endif /* IBMPC
  714.  
  715.     /* Actually, we should check each write for success */
  716.     return (KSUCCESS);
  717. bad:
  718.     return (KFAILURE);
  719. }
  720.  
  721.